Add build output manifest for static caching#262
Open
bcomnes wants to merge 6 commits into
Open
Conversation
Coverage Report for CI Build 27524398777Coverage increased (+0.3%) to 92.204%Details
Uncovered Changes
Coverage RegressionsNo coverage regressions found. Coverage Stats
💛 - Coveralls |
|
All alerts resolved. Learn more about Socket for GitHub. This PR previously contained dependency changes with security issues that have been resolved, removed, or ignored. |
31311d7 to
620a4bc
Compare
fb90546 to
e8c79b8
Compare
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
Add first-class service worker builds
e8c79b8 to
f665681
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This adds a first-class build output manifest for static app caching and pairs it with site service-worker support.
The goal is to let a domstack app build a fully static client, then have its own service worker consume a normalized, revisioned list of emitted files. Domstack provides the build facts; the application still owns service-worker registration, update UX, route filtering, offline behavior, and cache policy.
What Changed
domstack-output-manifest.json, written by one-shot builds by default.results.outputManifestfrom programmatic builds.report.outputsrecord collection.$schemaURL.json-schema-to-ts.manifest.settings.{js,mjs,cjs,ts,mts,cts}for build-output-manifest filtering policy.service-worker.{js,mjs,cjs,ts,mts,cts}anywhere undersrcbuilds to stable root/service-worker.js..npmignorewith apackage.json#filesallowlist.How The Manifest Works
Each build step records files as it emits them instead of trying to reconstruct the build from loosely shaped downstream reports. At the end of a one-shot build, domstack reconciles those records:
dest.revision.bytes,kind, and optional source/page metadata.excludepatterns andincludeOutput(entry)hooks.versionfrom cache-relevant fields:url,revision,kind, and page-levelprecache/offlinevars.$schema,version,generatedAt, andentries.The manifest intentionally does not expose local filesystem paths. It is a public serialized contract for deploy tools, service workers, and application code.
Manifest Shape
The written file looks like:
{ "$schema": "https://unpkg.com/@domstack/static@x.y.z/lib/build-output-manifest/schema.json", "version": "sha256-of-cache-relevant-output-metadata", "generatedAt": "2026-06-16T00:00:00.000Z", "entries": [ { "outputRelname": "index.html", "kind": "page", "url": "/", "revision": "sha256-file-content", "bytes": 1234 } ] }Entry
kindvalues are:New Public APIs
Build Results
Programmatic builds now return:
results.outputManifestis still returned when writing the JSON file is disabled withoutputManifest: false. Watch mode does not return an output manifest.CLI Options
Programmatic Options
Supported shape:
manifest.settings.*Apps can configure the generated manifest from a dedicated settings file anywhere under
src:This follows the existing Domstack settings-file pattern used by
esbuild.settings.*andmarkdown-it.settings.*. The default export can be an object, a sync function, or an async function returning an object.Use this when the app wants its build output manifest to reflect application policy, for example keeping admin pages, blog content, source maps, feeds, or other deployment-only files out of a PWA precache list.
Dynamic settings are supported too:
Supported shape:
How it is applied:
outputManifest.excludefrom CLI/programmatic config andmanifest.settings.*excludevalues are combined.entry.urlandentry.outputRelname.includeOutput(entry).includeOutput(entry)receives the public manifest entry shape, not internal filesystem details.domstack-output-manifest.jsonandresults.outputManifest.manifest.version, because versioning is based on the final cache-relevant entries.Useful entry fields for policy decisions:
Domstack records page-level
precacheandofflinevars onto page entries when present, but it does not interpret those flags itself. They are metadata for service workers, deployment tools, orincludeOutput(entry)policies.For example, a page can opt out of an app's offline policy:
Then the app's
includeOutput(entry)hook can decide whether that page entry should remain in the output manifest.Schema And Types
Domstack now exports:
The public
BuildOutputManifest,BuildOutputEntry,BuildOutputEntryPageMeta, andBuildOutputKindtypes are derived from those schemas and exported through the package type surface.Service Worker Support
Domstack now reserves one site service-worker source filename:
The source may live anywhere under
src, but only one is allowed. Multiple matches fail withDOM_STACK_ERROR_DUPLICATE_SERVICE_WORKER.The service worker is bundled through esbuild like the rest of the browser-side code, but it is emitted with a stable root output path:
That stable root URL matters because browsers check service-worker updates at the script URL, and root placement gives the worker root scope without requiring a
Service-Worker-Allowedheader.The built service worker is included in:
kind: 'service-worker'Browser Defines
Domstack injects these build facts into browser-side bundles:
process.env.DOMSTACK_OUTPUT_MANIFEST_URL/domstack-output-manifest.jsonprocess.env.DOMSTACK_OUTPUT_MANIFEST_ENABLED"true"for one-shot builds that write the manifest,"false"when disabled or in watch modeprocess.env.DOMSTACK_SERVICE_WORKER_URL/service-worker.js, or""when absentprocess.env.DOMSTACK_SERVICE_WORKER_SCOPE/, or""when absentA service worker can use the manifest URL at install time:
Application client code can register the worker from
global.client.js:Domstack does not inject registration into the default layout. Registration timing, update prompts, local-development opt-outs, poisoned-cache recovery, and offline route behavior are application policy.
Compatibility Notes
copyis now the output kind for files copied by the generic copy step.url/revisionpair, but this PR does not add a Workbox-specific generated artifact. There is a TODO to consider a derived Workbox manifest only after a concrete use case validates the API.domstack-output-manifest.jsonor returnresults.outputManifest; it does still build and rebundle the site service worker.Testing
node --test lib/identify-pages.test.js test-cases/general-features/index.test.jsnpm run test:tscnpm run test:neostandardnpm run build:declarationnpm run build:schemagit diff --check